package com.ryan.mdp.advice.service;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.jms.Message;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ryan.mdp.advice.AdviceLifecycle;
import com.ryan.mdp.constants.MessagePropertiesConstants;
import com.ryan.mdp.service.MdpContext;
import com.ryan.mdp.service.MdpContextHolder;

/**
 * 性能监控Advice
 * 
 * @author botao.liao
 * 
 */
public class MdpStatAdvice implements MethodInterceptor, AdviceLifecycle {
    private final Logger logger = LoggerFactory.getLogger(MdpStatAdvice.class);
    // 性能监测报告时间
    private static final long MDP_STAT_REPORT_RATE = 5 * 60;
    // 性能监控topic名称
    public static final String MDP_STAT_TOPIC = "mdp.stat.topic";
    private ScheduledExecutorService scheduler = null;

    // 服务IP
    private String serviceIP;
    // key:mdp interface, value:interface指标
    private final Map<MetricsKey, Metrics> metricsMap = new ConcurrentHashMap<MetricsKey, Metrics>();

    public Object invoke(MethodInvocation invocation) throws Throwable {
        MdpContext context = MdpContextHolder.currentContext();
        Message msg = context.getRequestMessage();
        String server = context.getServer();
        String source = msg.getStringProperty(MessagePropertiesConstants.MSG_PROPERTY_SOURCE);
        String sourceIp = msg.getStringProperty(MessagePropertiesConstants.MSG_PROPERTY_CLIENT_IP);
        String interfaze = invocation.getMethod().getDeclaringClass().getName();
        String method = invocation.getMethod().toString();
        MetricsKey key = new MetricsKey(server, getServiceIP(), source, sourceIp, interfaze, method);
        long beforeInvokeTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = invocation.proceed();
        } finally {
            long escapedTime = System.currentTimeMillis() - beforeInvokeTime;
            addServiceMetrics(key, escapedTime);
        }
        return result;
    }

    private void addServiceMetrics(MetricsKey key, long escapedTime) {
        Metrics metrics = metricsMap.get(key);
        if (metrics == null) {
            metrics = new Metrics(key);
            metricsMap.put(key, metrics);
        }
        metrics.add(escapedTime);
    }

    private String getServiceIP() {
        if (serviceIP == null) {
            try {
                serviceIP = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
            }
        }
        return serviceIP;
    }

    public void init() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                reportMdpStat();
            }
        }, MDP_STAT_REPORT_RATE, MDP_STAT_REPORT_RATE, TimeUnit.SECONDS);
    }

    public void destroy() {
        scheduler.shutdown();
    }

    /**
     * 性能定时报告，发送到jms topic里
     */
    private void reportMdpStat() {
        if (!metricsMap.isEmpty()) {
            logger.info("Mdp Stat Report:{}", metricsMap);
        }
    }
}
